﻿#region The MIT License (MIT)
// The MIT License (MIT)
// Copyright (c) 2010 - 2013 Sovacode LLC
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all copies or substantial portions
// of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion

using System;
using System.Diagnostics;

/* Importing namespaces */
using Sovacode.DemoApp.Model;
using Sovacode.DemoApp.ViewModel.BasicViewModel;
using Sovacode.RubiksCube.Common.Collections;
using Sovacode.RubiksCube.Common.Model;
using Sovacode.RubiksCube.Common.ViewModel;

namespace Sovacode.DemoApp.ViewModel
{
    /// <summary>
    /// Complex view model
    /// </summary>
    public sealed class ComplexViewModel : MainViewModel /* All view models should expose ViewModelTop or MainViewModel 
                                                          * 
                                                          * There two type of base view model class. The ViewModelTop is basic view model type.
                                                          * The Main View Model contains common properties such as Top, Left etc. for strogin and
                                                          * restoring position of main (or not) window.
                                                          * 
                                                          * Just add Top, Left, Right etc. into config file and bind it in XAML code of your
                                                          * window. You can find binding demo in MainWindow.xaml.
                                                          * 
                                                          * And tha's all.
                                                          * 
                                                          * In any case do not forget to save config file before closing application.
                                                          *  
                                                          */
    {
        #region Private fields

        private CommandsViewModel _commandsViewModel;
        private ConnectionStringsViewModel _connectionStringsViewModel;
        private SerializationViewModel _serializationViewModel;
        private SettingsViewModel _settingsViewModel;
        private SimpleValidationViewModel _simpleValidationViewModel;
        private ValidationManagerViewModel _validationManagerViewModel;
        private BehaviorViewModel _behaviorViewModel;

        private AdvancedObservableCollection<SimpleDataObject> _dataObjects;
        private int _selectedIndex = ViewModelConst.CommandsViewModelIndex;

        #endregion

        #region Selected View Model

        /// <summary>
        /// Selected index
        /// </summary>
        public int SelectedIndex
        {
            get { return _selectedIndex; }
            set
            {
                if (_selectedIndex == value)
                {
                    return;
                }

                _selectedIndex = value;

                OnPropertyChanged(() => SelectedIndex);
                OnPropertyChanged(() => Description);
            }
        }
       
        /// <summary>
        /// View Model Description
        /// </summary>
        public string Description
        {
            get { return SelectedView == null ? "No Description" : SelectedView.Description; }
        }

        #endregion

        #region Collection

        /// <summary>
        /// Shared collection of data objects
        /// </summary>
        private AdvancedObservableCollection<SimpleDataObject> DataObjects
        {
            get { return _dataObjects ?? (_dataObjects = CreateCollection()); }
        }

        #endregion

        #region View Models

        /// <summary>
        /// Gets the commands view model.
        /// </summary>
        /// <value>The commands view model.</value>
        public CommandsViewModel CommandsViewModel
        {
            get { return _commandsViewModel ?? (_commandsViewModel = CreateChildViewModel<CommandsViewModel>()); }
        }

        /// <summary>
        /// Gets the connection strings view model.
        /// </summary>
        /// <value>The connection strings view model.</value>
        public ConnectionStringsViewModel ConnectionStringsViewModel
        {
            get
            {
                return _connectionStringsViewModel ??
                       (_connectionStringsViewModel = CreateChildViewModel<ConnectionStringsViewModel>());
            }
        }

        /// <summary>
        /// Gets the serialization view model.
        /// </summary>
        /// <value>The serialization view model.</value>
        public SerializationViewModel SerializationViewModel
        {
            get
            {
                return _serializationViewModel ??
                       (_serializationViewModel = CreateChildViewModel<SerializationViewModel>());
            }
        }

        /// <summary>
        /// Gets the settings view model.
        /// </summary>
        /// <value>The settings view model.</value>
        public SettingsViewModel SettingsViewModel
        {
            get { return _settingsViewModel ?? (_settingsViewModel = CreateChildViewModel<SettingsViewModel>()); }
        }

        /// <summary>
        /// Gets the simple validation view model.
        /// </summary>
        /// <value>The simple validation view model.</value>
        public SimpleValidationViewModel SimpleValidationViewModel
        {
            get
            {
                return _simpleValidationViewModel ??
                       (_simpleValidationViewModel = CreateChildViewModel<SimpleValidationViewModel>());
            }
        }


        /// <summary>
        /// Gets the validation manager view model.
        /// </summary>
        /// <value>The validation manager view model.</value>
        public ValidationManagerViewModel ValidationManagerViewModel
        {
            get
            {
                return _validationManagerViewModel ??
                       (_validationManagerViewModel = CreateChildViewModel<ValidationManagerViewModel>());
            }
        }

        /// <summary>
        /// Gets the behavior view model.
        /// </summary>
        /// <value>The behavior view model.</value>
        public BehaviorViewModel BehaviorViewModel
        {
            get { return _behaviorViewModel ?? (_behaviorViewModel = CreateChildViewModel<BehaviorViewModel>()); }
        }

        #endregion

        #region Command Registration

        /// <summary>
        /// To register command need to override RegisterCommands() method of ViewModelTop class
        /// </summary>
        protected override void RegisterCommands()
        {
            base.RegisterCommands();

            RegisterCommand<string>(Commands.Const.MainView.NavigateTo, NavigateTo);
            RegisterCommand<SelectDirection>(Commands.Const.MainView.SelectTab, SelectTab);
        }

        /// <summary>
        /// Navigate to specific url
        /// </summary>
        /// <param name="url">Url</param>
        private void NavigateTo(string url)
        {
            Uri uri;

            Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out uri);

            if (uri == null)
            {
                ShowError("Url can not be empty!");

                return;
            }

            Process.Start(uri.AbsoluteUri);
        }

        #region Direction

        /// <summary>
        /// Select tab
        /// </summary>
        /// <param name="direction"><see cref="SelectDirection"/></param>
        private void SelectTab(SelectDirection direction)
        {
            if (direction == SelectDirection.Next)
            {
                MoveNext();

                return;
            }

            if (direction == SelectDirection.Back)
            {
                MoveBack();

                return;
            }
        }

        /// <summary>
        /// Back for one tab
        /// </summary>
        private void MoveBack()
        {
            if (SelectedIndex == ViewModelConst.CommandsViewModelIndex)
            {
                SelectedIndex = ViewModelConst.BehaviorViewModelIndex;

                return;
            }

            SelectedIndex--;
        }

        /// <summary>
        /// Next for one tab
        /// </summary>
        private void MoveNext()
        {
            if (SelectedIndex == ViewModelConst.BehaviorViewModelIndex)
            {
                SelectedIndex = ViewModelConst.CommandsViewModelIndex;

                return;
            }

            SelectedIndex++;
        }

        #endregion

        #endregion

        #region Private methods

        /// <summary>
        /// Selected View Model <see cref="ChildsHolderViewModel"/>
        /// </summary>
        private ChildsHolderViewModel SelectedView
        {
            get { return GetSelectedViewModel(); }
        }

        /// <summary>
        /// Get Selected View by Index
        /// </summary>
        /// <returns>Selected View <see cref="ChildsHolderViewModel"/></returns>
        private ChildsHolderViewModel GetSelectedViewModel()
        {
            switch (SelectedIndex)
            {
                case ViewModelConst.CommandsViewModelIndex:
                    {
                        return CommandsViewModel;
                    }
                case ViewModelConst.SimpleValidationViewModelIndex:
                    {
                        return SimpleValidationViewModel;
                    }
                case ViewModelConst.ValidationManagerViewModelIndex:
                    {
                        return ValidationManagerViewModel;
                    }
                case ViewModelConst.SettingsViewModelIndex:
                    {
                        return SettingsViewModel;
                    }
                case ViewModelConst.ConnectionStringsViewModelIndex:
                    {
                        return ConnectionStringsViewModel;
                    }
                case ViewModelConst.SerializationViewModelIndex:
                    {
                        return SerializationViewModel;
                    }
                case ViewModelConst.BehaviorViewModelIndex:
                    {
                        return BehaviorViewModel;
                    }
            }

            throw new ArgumentOutOfRangeException("SelectedIndex");
        }

        /// <summary>
        /// Create view model with specific type
        /// </summary>
        /// <typeparam name="T">Specific type of view model <see cref="ChildsHolderViewModel"/></typeparam>
        /// <returns>New view model with specific type</returns>
        private T CreateChildViewModel<T>()
            where T : ChildsHolderViewModel, new()
        {
            return new T { WindowService = this.WindowService, SettingsManager = this.SettingsManager, DataObjects = this.DataObjects };
        }

        /// <summary>
        /// Create collection with data objects
        /// </summary>
        /// <returns>Collection <see cref="AdvancedObservableCollection{T}"/></returns>
        private AdvancedObservableCollection<SimpleDataObject> CreateCollection()
        {
            return new AdvancedObservableCollection<SimpleDataObject>
                       {
                           new SimpleDataObject { Name = "Firefly"},
                           new SimpleDataObject { Name = "Blade Runner"},
                           new SimpleDataObject { Name = "Event Horizon"},
                           new SimpleDataObject { Name = "Torchwood"},
                       };
        }

        #endregion

        #region Nested class

        /// <summary>
        /// Nested const static class
        /// </summary>
        private static class ViewModelConst
        {
            /// <summary>
            /// Commands View Model Index
            /// </summary>
            internal const int CommandsViewModelIndex = 0;
            /// <summary>
            /// Simple Validation View Model Index
            /// </summary>
            internal const int SimpleValidationViewModelIndex = 1;
            /// <summary>
            /// Validation Manager View Model Index
            /// </summary>
            internal const int ValidationManagerViewModelIndex = 2;
            /// <summary>
            /// Settings View Model Index
            /// </summary>
            internal const int SettingsViewModelIndex = 3;
            /// <summary>
            /// Connection Strings View Model Index
            /// </summary>
            internal const int ConnectionStringsViewModelIndex = 4;
            /// <summary>
            /// Serialization View Model Index
            /// </summary>
            internal const int SerializationViewModelIndex = 5;
            /// <summary>
            /// Behavior View Model Index
            /// </summary>
            internal const int BehaviorViewModelIndex = 6;
        }

        #endregion
    }
}